/*
 * @Author: xiaosihan 
 * @Date: 2021-04-15 00:34:44 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2022-06-08 14:33:45
 */

import Dexie, { Table } from "dexie";
import _ from "lodash";
import { Font, FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import xrt_util from "../xrt_util/xrt_util";
import FontConfig from "./FontConfig";
import gentilisJSON from "./gentilis.json";

export type saveFontParam = {
    fontType?: string,
    fontName: string,
    fontJson: any
}

export type addFontFamilyParam = {
    fontType?: string,
    fontFamilyJson: any
}

export type getFontParam = {
    fontType?: string,
    fontName: string
}

export type loadTextParam = {
    fontType?: string,
    text?: string,
    callback?: (font: Font) => void
}

class indexBD extends Dexie {
    constructor(dbName: string) {
        super(dbName)
    }
    threeFont!: Table;
}

// 字体加载器
class fontContorl {

    constructor() { }

    THREEFontMap: Map<string, Font> = new Map();

    // 专门存储字体的数据库
    fontBD: indexBD = (() => {

        let fontDB = new indexBD("xsh-react-three-font");

        fontDB.version(1).stores({ threeFont: "++KeyPath,fontType,fontName,fontJson" });
        return fontDB;
    })();


    /**
     * 保存 字体json到本地数据库中
     * @param {saveFontParam} { fontType = "simhei", fontName, fontJson }
     * @memberof fontContorl
     */
    async saveFont({ fontType = "simhei", fontName, fontJson = "" }: saveFontParam) {

        let findResult = await this.getFont({ fontType, fontName });

        if (_.isEmpty(findResult)) {
            await this.fontBD.threeFont.add({ fontType, fontName, fontJson });
        }
    }

    /**
     * 通过 fontType 和 fontName 查询 fontJson
     * @param {getFontParam} { fontType = "simhei", fontName }
     * @returns
     * @memberof fontContorl
     */
    async getFont({ fontType = "simhei", fontName }: getFontParam) {

        let fondResult = await this.fontBD.threeFont
            .filter(d => (d.fontType === fontType && d.fontName === fontName))
            .toArray();

        if (_.isEmpty(fondResult)) {
            return undefined;
        } else {
            return _.first(fondResult).fontJson;
        }

    }

    // 加载字体的回调函数们
    _loadTextCall: Map<string, Array<() => void>> = new Map();

    // 加载文字 提供给需要创建字体模型的方法使用 以节流的形式调用 回调函数
    async loadText({ fontType = "simhei", text = "", callback }: loadTextParam) {

        // 加载字体容器
        await this._loadFontIndexJson({ fontType });

        let newCallback = () => {
            let fontFamily = this.THREEFontMap.get(fontType);
            if (callback && fontFamily) {
                callback(fontFamily);
            }
        }

        // 遍历文本
        _.filter(text).map(fontName => {

            // 没有的就去加载
            if (!this.hasFont({ fontType, fontName })) {

                // 添加文字的默认模型 避免报错
                let fontFamily = this.THREEFontMap.get(fontType);

                // 创建 three 字体对象
                if (fontFamily) {
                    //@ts-ignore
                    fontFamily.data.glyphs[fontName] = { "ha": 1389, "x_min": 477, "x_max": 949, "o": "m 700 901 q 906 770 830 906 q 770 477 949 618 q 711 288 711 412 l 613 288 q 781 608 613 494 q 819 722 825 651 q 700 808 808 803 l 684 808 q 581 673 575 803 l 477 673 q 613 884 477 836 q 700 901 629 901 m 732 184 l 732 71 l 591 71 l 591 184 l 732 184 z " }
                }

                this._loadFontJson({ fontType, fontName });
            }

            // 加入待执行的回调
            let origin_callbacks = this._loadTextCall.get(`${fontType}_${fontName}`) || [];

            if (newCallback) {
                this._loadTextCall.set(`${fontType}_${fontName}`, [...origin_callbacks, newCallback]);
            }
        });

        // 执行任务队列
        xrt_util.requestAnimationFrame(newCallback);
    }

    // 加载字体
    async _loadFontIndexJson({ fontType = "simhei" }: loadTextParam) {

        let fontFamily = this.THREEFontMap.get(fontType);

        // 创建 three 字体对象
        if (!fontFamily) {

            // 初始字体结构
            fontFamily = new Font({
                "underlineThickness": 69,
                "underlinePosition": -174,
                "resolution": 1000,
                "original_font_information": {},
                "familyName": "Source Han Sans CN Normal",
                "descender": -167,
                "cssFontWeight": "normal",
                "cssFontStyle": "normal",
                "boundingBox": {
                    "yMin": -1456,
                    "xMin": -1389,
                    "yMax": 2511,
                    "xMax": 4067
                },
                "glyphs": {}
            });

            this.THREEFontMap.set(fontType, fontFamily);

            // 读取本地数据库中的字体初始结构文件
            let fontFamilyIndexJson = await this.getFont({ fontType, fontName: "index" });

            // 加载外部字体初始结构文件
            if (!fontFamilyIndexJson) {
                this._loadFontJson({ fontType, fontName: "index" });
            }
        }
    }

    // 加载外部字体.js
    async _loadFontJson({ fontType = "simhei", fontName }: { fontType: string, fontName: string }) {

        let fontJson = await this.getFont({ fontType, fontName });

        if (!fontJson) {
            fontJson = (gentilisJSON as any).glyphs[fontName];
        }

        // 数据库中没有 就去加载字体js
        if (!fontJson) {

            // 加载字体js 
            await new Promise<void>(resolve => {

                let script = document.createElement("script");

                Object.assign(script, {
                    type: "text/javascript",
                    src: `${FontConfig.path}${fontType}/${fontName}.js`,
                    async: true,
                    onload: () => {
                        script.remove();
                        resolve();
                    },
                    onerror: () => {
                    }
                });
                document.head.appendChild(script);
            });

        } else {
            // 数据库或者默认字体中 有就加入字体文件中
            let fontFamily = this.THREEFontMap.get(fontType);

            // 创建 three 字体对象
            if (fontFamily) {
                //@ts-ignore
                fontFamily.data.glyphs[fontName] = fontJson;
            }
        }

        // 执行相应的回调函数
        let origin_callbacks = this._loadTextCall.get(`${fontType}_${fontName}`) || [];

        // // 删除待执行的回调
        this._loadTextCall.delete(`${fontType}_${fontName}`);

        origin_callbacks.map(callback => {

            // 执行任务队列
            xrt_util.requestAnimationFrame(callback);
        });
    }

    hasFont({ fontType, fontName }: { fontType: string, fontName: string }) {
        return !_.isEmpty(
            this.THREEFontMap.get(fontType) &&
            //@ts-ignore
            this.THREEFontMap.get(fontType).data.glyphs[fontName]
        );
    }

    // 这个方法是提供给外部字体文件调用的
    addFont({ fontType = "simhei", fontName, fontJson }: saveFontParam) {

        // 保存字体json到本地数据中
        this.saveFont({ fontType, fontName, fontJson });

        let fontFamily = this.THREEFontMap.get(fontType);

        // 创建 three 字体对象
        if (fontFamily) {
            //@ts-ignore
            fontFamily.data.glyphs[fontName] = fontJson;
        }
    }

    // 这个方法是提供给外部字体文件调用的
    addFontFamily({ fontType = "simhei", fontFamilyJson }: addFontFamilyParam) {

        // 保存字体初始结构到数据库中
        this.saveFont({ fontType, fontName: "index", fontJson: fontFamilyJson });

        let fontFamily = this.THREEFontMap.get(fontType);

        // 创建 three 字体对象
        if (fontFamily) {
            //@ts-ignore
            fontFamily.data = {
                ...fontFamilyJson,
                //@ts-ignore
                glyphs: fontFamily.data.glyphs
            }
        }

    }

}

const fontContorller = new fontContorl();

Object.assign(window, { fontContorller });

export default fontContorller;